package bom.example.common.system.controller;

import bom.example.common.common.Contants;
import bom.example.common.common.Results;
import bom.example.common.system.domain.SysFile;
import bom.example.common.system.service.SysFileService;
import bom.example.common.utils.PathUtils;
import bom.example.common.utils.SysFileUtils;
import com.alibaba.druid.support.json.JSONUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * @author X.I.O
 * @title: FileController
 * @projectName springboot
 * @description: TODO
 * @date 2021/10/28 20:37
 */
@Api(tags = {"文件服务"})
@RestController
@RequestMapping("file")
public class FileController {

    @Autowired
    private SysFileService sysFileService;

    @PostMapping("/upload")
    @ApiOperation("文件上传服务")
    public JSONObject uploadFileController(MultipartFile file){
        File path= PathUtils.getPathByName("file");
        SysFile sysFile=SysFileUtils.getSysFileByMultipartFile(file,path);
        if(sysFile!=null){
            sysFileService.save(sysFile);
            String fileUrl=SysFileUtils.getDownLoadUrlBySysFile(sysFile);
            return Results.success(fileUrl);
        }
        return Results.success("上传失败");
    }

    @PostMapping("filelist")
    @ApiOperation("文件列表")
    public JSONObject selectFileController(@ApiParam("页码") @RequestParam(value = "pageNum",defaultValue = "1")Integer pageNum,
                                          @ApiParam("条数") @RequestParam(value = "pageSize",defaultValue = "10")Integer pageSize,
                                          @ApiParam("关键字") @RequestParam(value = "keyword",required = false)String keyword){
        LambdaQueryWrapper<SysFile> lambdaQueryWrapper=new LambdaQueryWrapper();
        if(StringUtils.isNotBlank(keyword)){
            lambdaQueryWrapper.or().like(SysFile::getFileName,keyword);
            lambdaQueryWrapper.or().like(SysFile::getFileType,keyword);
        }
        Page page=new Page(pageNum,pageSize);
        IPage<SysFile> iPage=sysFileService.page(page,lambdaQueryWrapper);
        List<SysFile> mapList=iPage.getRecords();
        List<JSONObject> jsonObjects=new ArrayList<>();
        for (int i = 0; i < mapList.size() ; i++) {
            SysFile map=mapList.get(i);
            JSONObject jsonObject=(JSONObject) JSON.toJSON(map);
            String url= Contants.SYSTEM_URL+SysFileUtils.getDownLoadUrlBySysFile(map);
            jsonObject.put("url",url);
            jsonObjects.add(jsonObject);
        }
        return Results.success(jsonObjects,iPage.getTotal());
    }


    @GetMapping("/download/{id}")
    @ApiOperation("文件下载")
    public void donloadController(HttpServletRequest request,HttpServletResponse response,
                           @PathVariable("id") String id,
                           // 获取Header里面的Range内容, 可选项, 可为空
                           @RequestHeader(name = "Range", required = false) String range) {
        SysFile sysFile=sysFileService.getById(id);
        // 测试用文件
        File file = new File(sysFile.getFilePath());

        // 设置Content-Type, 此处可以参考void org.apache.catalina.startup.Tomcat.addDefaultMimeTypeMappings(Context context)
        // 采用的是扩展名判断Content-Type, 内容可以参考org.apache.catalina.startup.MimeTypeMappings.properties
        String mimeType = request.getServletContext().getMimeType(sysFile.getFileName());
        response.setContentType(null != mimeType ? mimeType : "application/octet-stream; charset=UTF-8");
        // 自定义文件名
        response.setHeader("Content-Disposition", String.format("attachment; filename=%s", sysFile.getFileName()));
        response.setHeader("Accept-Ranges", "bytes");

        try (
                // 获取Response输出流
                ServletOutputStream out = response.getOutputStream();
                // 测试用文件出入流
                InputStream fis = new FileInputStream(file);) {
            // fis.available()可以获取有限数据流总大小, 但available()返回的是int类型, 适用于小于2 G的文件
            // file.length()可以获取文件大小, 返回的是long类型, 适用于小于8.4215048E7 P的文件
            // 获取数据流总大小
            long length = file.length();
            // 定义有效数据流起始, 截止位置
            long from = 0, to = length - 1;
            if (null == range) {
                response.setHeader("Content-Length", Long.toString(length));
            } else {
                response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
                String[] ranges = range.replace("bytes=", "").split("-");
                if (ranges.length > 0){
                    from = Long.parseLong(ranges[0]);
                }
                if (ranges.length > 1) {
                    to = Long.parseLong(ranges[1]);
                }
                // 设置本批次数据大小
                response.setHeader("Content-Length", Long.toString(to - from + 1L));
                // 设置本批次数据范围及数据总大小
                response.setHeader("Accept-Ranges", String.format("bytes %d-%d/%d", from, to, length));
            }
            // 跳过不需要的数据内容
            fis.skip(from);
            // 限制数据流大小, 最大等于文件大小
            long limit = to - from + 1;
            // 缓冲大小
            int bufferSize = (int) (limit > 2048 ? 2048 : limit);
            // 创建缓冲数组
            byte[] buffer = new byte[bufferSize];
            int num = 0;
            while (0 < limit && (num = fis.read(buffer)) != -1) {
                out.write(buffer, 0, num);
                limit -= num;
                if (limit < bufferSize) {
                    buffer = new byte[(int) limit];
                }
            }
            response.flushBuffer();
        } catch (IOException e) {
            // TODO :: [远程主机强迫关闭了一个现有的连接。]... 等异常处理
        }

    }

}
